#include "StdAfx.h"
#include "VSqlTable.h"

// VSqlTablesReg //////////////////////////////////////////////////////////////

//
void VSqlTablesReg::registerInDb()
{
	QSqlDatabase db = VSqlDatabase::main();
	db.transaction();

	foreach (VSqlTableReg *p,singleton()->m_list) {
		p->registerInDb();
	}

	db.commit();
}

// VSqlTableModel /////////////////////////////////////////////////////////////

//
VSqlTableModel::VSqlTableModel(QObject *parent) 
	:QSqlTableModel(parent) 
{
}

//
Qt::ItemFlags VSqlTableModel::flags(const QModelIndex &index) const
{
	//return QSqlTableModel::flags(index);
	//if (!index.isValid())
	//	return 0;

	return Qt::ItemIsEnabled | Qt::ItemIsSelectable; // | Qt::ItemIsEditable;
}

//
QVariant VSqlTableModel::headerData(int section,Qt::Orientation orientation,int role) const
{
	if (orientation == Qt::Vertical)
	{
		switch (role)
		{
			case Qt::DisplayRole:
			{
				return QVariant();
			}
			break;
		}
	}

	return QSqlTableModel::headerData(section,orientation,role);
}

//
QVariant VSqlTableModel::data(const QModelIndex &index,int role) const
{
	QVariant value = QSqlTableModel::data(index,role);

	switch (role)
	{
		case Qt::DisplayRole: 
		case Qt::EditRole: 
		{
			QVariant value = QSqlTableModel::data(index,role);
			return value.isNull() ? QVariant("<null>") : value;
		}
		break;

		case Qt::TextColorRole:
		{
			QVariant value = QSqlTableModel::data(index,Qt::DisplayRole);
			if (value.isNull()) {
				return QColor(255,0,0);
			}
		}
		break;
		
		case Qt::TextAlignmentRole:
		{
			//return int(Qt::AlignRight	|	Qt::AlignVCenter);
		
		}
		break;
	}

	return QSqlTableModel::data(index,role);
}

// VSqlTable //////////////////////////////////////////////////////////////////

//
VSqlTable::VSqlTable(const QString &tableName)
	:m_tableInfoIsSelect(false)
	,m_name(tableName)
{ 
	m_fieldInfo = new VSqlFieldInfo;
	m_fieldsPtr = VSqlFieldsPtr(new VSqlFields);
}

//
VSqlTable::~VSqlTable()
{ 
	delete m_fieldInfo;
}

//
QString VSqlTable::selectRecordsAsSql(const QString &sqlOrderBy) const
{
	VSqlFields fields = selectFields();
	if (fields.count() == 0) {
		return QString();
	}

	QString sFields;
	foreach (const VSqlFieldPtr field,fields) {
		if (field->eType() == VSqlFieldType::EType_listId) {
			continue;
		}
		sFields += field->name() + ",";
	}
	sFields.remove(sFields.count()-1,1);

	QString sql
		= " select " + sFields
		+ " from " + m_name
	;

	if (!sqlOrderBy.isEmpty()) {
		sql += " order by " + sqlOrderBy;
	}

	return sql;
}

//
void VSqlTable::registerInDb() 
{
	QSqlDatabase db = VSqlDatabase::main();
	QSqlRecord dbFields = db.record(m_name);
	VSqlFields selFields = selectFields();
	VSqlFields createFields,addFields,insFields,mRefFields;//,updateFields;

	foreach (VSqlFieldPtr field,*m_fieldsPtr) {
		if (!selFields.findFieldByName(field->name())) {
			insFields.append(field);
		}

		if (field.objectCast<VSqlFieldListId>()) {
			mRefFields.append(field);		
		}
		else {
			if (dbFields.count()) {
				if (!dbFields.contains(field->name())) {
					addFields.append(field);
				}
				//else if
			}
			else {
				createFields.append(field);
			}
		}
	}

	if (createFields.count()) {
		createTable(m_name,createFields);
	}
	
	if (addFields.count()) {
		QString sAdd;
		foreach (VSqlFieldPtr field,addFields) {
			sAdd += " add " + field->name() + " " + field->sqlType() + ",";
		}
		sAdd.remove(sAdd.count()-1,1);

		QSqlQuery qry(db);
		QString sql = "alter table " + m_name + " " + sAdd;

		bool isOk = qry.exec(sql);
		Q_ASSERT(isOk);
	}

	if (insFields.count()) {
		VSqlRegTables::insertFields(m_name,insFields);
	}

	if (mRefFields.count()) {
		VSqlTableListId::registerInDb(m_name);
	}
}

//
VSqlFields VSqlTable::selectFields() const 
{
	QList<QSqlRecord> records = VSqlRegTables::selectFieldsAsRecords(m_name);
	VSqlFields fields;
	
	foreach (const QSqlRecord record,records) {
		VSqlFieldPtr field = VSqlFields::factoryField(
			(VSqlFieldType::EType)record.value(VSqlRegTables::fFieldType()).toInt()
		);
		field->fromRecord(record);
		fields.append(field);
	}

	return fields;
}

//
QList<QSqlRecord> VSqlTable::selectRecords(const QString &sqlWhere) const
{
	QString sql
		= " select " + selectFields().sqlFieldsName()
		+ " from " + m_name
	;
	
	if (!sqlWhere.isEmpty()) {
		sql += " where " + sqlWhere;
	}
	
	QSqlQuery qry(VSqlDatabase::main());
	bool ok = qry.prepare(sql);
	Q_ASSERT(ok);

	qry.exec();
	QList<QSqlRecord> records;

	while (qry.next()) {
		records << qry.record();
	}
	
	return records;
}

//
void VSqlTable::updateRecords(const QSqlRecord &record,const QString &sqlWhere)
{
	if (record.count() == 0) {
		return;
	}
	
	QString sFields;
	
	for (int i = 0; i < record.count(); ++i) {
		QString fName = record.fieldName(i);
		sFields += fName + " = :" + fName + ",";
	}

	sFields.remove(sFields.count()-1,1);

	QString sql
		= " update " + m_name
		+ " set " + sFields
	;
	
	if (!sqlWhere.isEmpty()) {
		sql += " where " + sqlWhere;
	}
	
	QSqlQuery qry(VSqlDatabase::main());
	bool ok = qry.prepare(sql);
	Q_ASSERT(ok);
	
	for (int i = 0; i < record.count(); ++i) {
		QString fName = record.fieldName(i);
		QVariant value = record.value(i);
		
		qry.bindValue(fName,value);
	}
	
	ok = qry.exec();
	Q_ASSERT(ok);
}

//
VSqlFieldPtr VSqlTable::toFieldFrom(const VSqlFieldRefIdPtr &fieldRefId)
{
	VSqlTable toTable;
		toTable.setName(fieldRefId->toTableName());
	VSqlFields toFields = toTable.selectFields();

	if (fieldRefId->toFieldName().isEmpty()) {
		VSqlFieldPtr toField = toFields.findFieldByEType(VSqlFieldType::EType_idAuto);
		if (toField) {
			return toField;
		}
	}
	else {
		VSqlFieldPtr toField = toFields.findFieldByName(fieldRefId->toFieldName());
		if (toField) {
			return toField;
		}
	}

	return VSqlFieldPtr();
}

//
VSqlFieldPtr VSqlTable::toFieldFrom(const VSqlFieldRefStringPtr &fieldRef)
{
	VSqlTable toTable;
		toTable.setName(fieldRef->toTableName());
	VSqlFields toFields = toTable.selectFields();

	if (!fieldRef->toFieldName().isEmpty()) {
		VSqlFieldPtr toField = toFields.findFieldByName(fieldRef->toFieldName());
		if (toField) {
			return toField;
		}
	}

	return VSqlFieldPtr();
}

//
VSqlFieldPtr VSqlTable::toFieldFrom(const VSqlFieldListIdPtr &fieldListId)
{
	VSqlTable toTable;
		toTable.setName(fieldListId->toTableName());
	VSqlFields toFields = toTable.selectFields();

	if (fieldListId->toFieldName().isEmpty()) {
		VSqlFieldPtr toField = toFields.findFieldByEType(VSqlFieldType::EType_idAuto);
		if (toField) {
			return toField;
		}
	}
	else {
		VSqlFieldPtr toField = toFields.findFieldByName(fieldListId->toFieldName());
		if (toField) {
			return toField;
		}
	}

	return VSqlFieldPtr();
}

// VSqlTableListId ////////////////////////////////////////////////////////////

//
void VSqlTableListId::registerInDb(const QString &tableName)
{
	VSqlTable table;
		table.setName(tName(tableName));

	table.fieldsPtr()->append(
		VSqlFieldRefId().setName(fId()).setToTableName(tableName)
	);
	table.fieldsPtr()->append(
		VSqlFieldString().setName(fToTableName())
	);
	table.fieldsPtr()->append(
		VSqlFieldId().setName(fToId())
	);

	table.registerInDb();
}

///////////////////////////////////////////////////////////////////////////////
// VSqlRegTablesDN ////////////////////////////////////////////////////////////

VSqlRegTablesDN VSqlRegTablesDN::m_singleton(VSqlTablesReg::singleton());

//
void VSqlRegTablesDN::registerInDb()
{
	VSqlTable table;
		table.setName(tName());

	table.fieldsPtr()->append(
		VSqlFieldRefString()
			.setName(fUnicode())
			.setToTableName(VSqlRegTables::tName())
			.setToFieldName(VSqlRegTables::fUnicode())
	);

	table.fieldsPtr()->append(
		VSqlFieldInteger().setName(fLang())
	);

	table.fieldsPtr()->append(
		VSqlFieldString().setName(fDisplayName()).setMaxLength(20)
	);

	table.registerInDb();
}

// VSqlRegTablesACT ///////////////////////////////////////////////////////////

VSqlRegTablesACT VSqlRegTablesACT::m_singleton(VSqlTablesReg::singleton());

//
void VSqlRegTablesACT::registerInDb()
{
	VSqlTable table;
		table.setName(tName());

	table.fieldsPtr()->append(
		VSqlFieldRefString()
			.setName(fUnicode())
			.setToTableName(VSqlRegTables::tName())
			.setToFieldName(VSqlRegTables::fUnicode())
	);

	table.fieldsPtr()->append(
		VSqlFieldInteger().setName(fInsert())
	);
	table.fieldsPtr()->append(
		VSqlFieldInteger().setName(fDelete())
	);
	table.fieldsPtr()->append(
		VSqlFieldInteger().setName(fUpdate())
	);
	table.fieldsPtr()->append(
		VSqlFieldInteger().setName(fSelect())
	);

	table.registerInDb();
}

// VSqlRegTablesFORM //////////////////////////////////////////////////////////

VSqlRegTablesFORM VSqlRegTablesFORM::m_singleton(VSqlTablesReg::singleton());

//
void VSqlRegTablesFORM::registerInDb()
{
	VSqlTable table;
		table.setName(tName());

	table.fieldsPtr()->append(
		VSqlFieldRefString()
			.setName(fUnicode())
			.setToTableName(VSqlRegTables::tName())
			.setToFieldName(VSqlRegTables::fUnicode())
	);

	table.fieldsPtr()->append(
		VSqlFieldString().setName(fFormName()).setMaxLength(20)
	);

	table.fieldsPtr()->append(
		VSqlFieldText().setName(fScript())
	);

	table.registerInDb();
}

/*
// VSqlRegTablesExt ///////////////////////////////////////////////////////////

VSqlRegTablesExt VSqlRegTablesExt::m_singleton(VSqlTablesReg::singleton());

//
void VSqlRegTablesExt::registerInDb()
{
	//VRegTablesExt
	//	regTables<VRegTables>	forms<VForms>	actions<VActions>

	VSqlTable table;
		table.setName(tName());

	table.fieldsPtr()->append(
		VSqlFieldSRef().setName(fRegTables()).setToTableName(VSqlRegTables::tName())
	);

	table.fieldsPtr()->append(
		VSqlFieldMRef().setName(fDisplayName()).setToTableName(VSqlRegTablesDN::tName())
	);

	table.fieldsPtr()->append(
		VSqlFieldMRef().setName(fForms()).setToTableName(VSqlRegTablesFORM::tName())
	);

	table.fieldsPtr()->append(
		VSqlFieldMRef().setName(fActions()).setToTableName(VSqlRegTablesACT::tName())
	);

	table.registerInDb();
}
*/